﻿using System;
using System.Collections.Generic;
using System.Text;

namespace CoreRay
{
    public abstract class ParametricSurface : Mesh
    {
        private int segments;

        protected ParametricSurface()
        {
            this.Segments = 32;
        }

        public int Segments
        {
            get
            {
                return this.segments;
            }

            set
            {
                this.segments = value;
                this.Generate();
            }
        }

        protected void Generate()
        {
            // Init vertex format
            VertexFormat vertexFormat = new VertexFormat();
            vertexFormat.AddElement("Position", typeof(Vector3));
            vertexFormat.AddElement("Normal", typeof(Vector3));
            vertexFormat.AddElement("TextureCoordinates", typeof(Vector2));
            
            // Init geometry buffer
            this.GeometryBuffer = new GeometryBuffer(vertexFormat);

            float step = 1.0f / (this.Segments - 1);

            for (int i = 0; i < this.Segments; i++)
            {
                for (int j = 0; j < this.Segments; j++)
                {
                    Vector3 position = ComputeVertexPosition(j * step, i * step);
                    Vector3 normal = ComputeVertexNormal(j * step, i * step);
                    
                    this.GeometryBuffer.VertexBuffer.Write(position);
                    this.GeometryBuffer.VertexBuffer.Write(normal);
                    this.GeometryBuffer.VertexBuffer.Write(new Vector2(j * step, i * step));
                    
                    if (j < this.Segments - 1 && i < this.Segments - 1)
                    {
                        this.GeometryBuffer.IndexBuffer.Write(i * this.Segments + j + 1);
                        this.GeometryBuffer.IndexBuffer.Write(i * this.Segments + j);
                        this.GeometryBuffer.IndexBuffer.Write((i + 1) * this.Segments + j);

                        this.GeometryBuffer.IndexBuffer.Write(i * this.Segments + j + 1);
                        this.GeometryBuffer.IndexBuffer.Write((i + 1) * this.Segments + j);
                        this.GeometryBuffer.IndexBuffer.Write((i + 1) * this.Segments + j + 1);
                    }
                }
            }

            this.Commit();
        }

        protected abstract Vector3 ComputeVertexPosition(float s, float t);

        protected abstract Vector3 ComputeVertexNormal(float s, float t);
    }
}
